/**
 * @license BSD
 * @copyright 2014-2023 hizzgdev@163.com
 *
 * Project Home:
 *   https://github.com/hizzgdev/jsmind/
 */

(function ($w) {
  "use strict";
  console.warn("The version is outdated. see details: https://hizzgdev.github.io/jsmind/es6/README.md");
  var __name__ = "jsMind";
  var jsMind = $w[__name__];
  if (!jsMind) {
    return;
  }
  if (typeof jsMind.screenshot != "undefined") {
    return;
  }

  var $d = $w.document;
  var $c = function (tag) {
    return $d.createElement(tag);
  };

  var css = function (cstyle, property_name) {
    return cstyle.getPropertyValue(property_name);
  };
  var is_visible = function (cstyle) {
    var visibility = css(cstyle, "visibility");
    var display = css(cstyle, "display");
    return visibility !== "hidden" && display !== "none";
  };
  var jcanvas = {};
  jcanvas.rect = function (ctx, x, y, w, h, r) {
    if (w < 2 * r) r = w / 2;
    if (h < 2 * r) r = h / 2;
    ctx.moveTo(x + r, y);
    ctx.arcTo(x + w, y, x + w, y + h, r);
    ctx.arcTo(x + w, y + h, x, y + h, r);
    ctx.arcTo(x, y + h, x, y, r);
    ctx.arcTo(x, y, x + w, y, r);
  };

  jcanvas.text_multiline = function (ctx, text, x, y, w, h, lineheight) {
    var line = "";
    var text_len = text.length;
    var chars = text.split("");
    var test_line = null;
    ctx.textAlign = "left";
    ctx.textBaseline = "top";
    for (var i = 0; i < text_len; i++) {
      test_line = line + chars[i];
      if (ctx.measureText(test_line).width > w && i > 0) {
        ctx.fillText(line, x, y);
        line = chars[i];
        y += lineheight;
      } else {
        line = test_line;
      }
    }
    ctx.fillText(line, x, y);
  };

  jcanvas.text_ellipsis = function (ctx, text, x, y, w, h) {
    var center_y = y + h / 2;
    var text = jcanvas.fittingString(ctx, text, w);
    ctx.textAlign = "left";
    ctx.textBaseline = "middle";
    ctx.fillText(text, x, center_y, w);
  };

  jcanvas.fittingString = function (ctx, text, max_width) {
    var width = ctx.measureText(text).width;
    var ellipsis = "…";
    var ellipsis_width = ctx.measureText(ellipsis).width;
    if (width <= max_width || width <= ellipsis_width) {
      return text;
    } else {
      var len = text.length;
      while (width >= max_width - ellipsis_width && len-- > 0) {
        text = text.substring(0, len);
        width = ctx.measureText(text).width;
      }
      return text + ellipsis;
    }
  };

  jcanvas.image = function (ctx, url, x, y, w, h, r, rotation, callback) {
    var img = new Image();
    img.onload = function () {
      ctx.save();
      ctx.translate(x, y);
      ctx.save();
      ctx.beginPath();
      jcanvas.rect(ctx, 0, 0, w, h, r);
      ctx.closePath();
      ctx.clip();
      ctx.translate(w / 2, h / 2);
      ctx.rotate((rotation * Math.PI) / 180);
      ctx.drawImage(img, -w / 2, -h / 2);
      ctx.restore();
      ctx.restore();
      !!callback && callback();
    };
    img.src = url;
  };

  jsMind.screenshot = function (jm) {
    this.jm = jm;
    this.canvas_elem = null;
    this.canvas_ctx = null;
    this._inited = false;
  };

  jsMind.screenshot.prototype = {
    init: function () {
      if (this._inited) {
        return;
      }
      console.log("init");
      var c = $c("canvas");
      var ctx = c.getContext("2d");

      this.canvas_elem = c;
      this.canvas_ctx = ctx;
      this.jm.view.e_panel.appendChild(c);
      this._inited = true;
      this.resize();
    },

    shoot: function (callback) {
      this.init();
      this._draw(
        function () {
          !!callback && callback();
          this.clean();
        }.bind(this),
      );
      this._watermark();
    },

    shootDownload: function () {
      this.shoot(
        function () {
          this._download();
        }.bind(this),
      );
    },

    shootAsDataURL: function (callback) {
      this.shoot(
        function () {
          !!callback && callback(this.canvas_elem.toDataURL());
        }.bind(this),
      );
    },

    resize: function () {
      if (this._inited) {
        this.canvas_elem.width = this.jm.view.size.w;
        this.canvas_elem.height = this.jm.view.size.h;
      }
    },

    clean: function () {
      var c = this.canvas_elem;
      this.canvas_ctx.clearRect(0, 0, c.width, c.height);
    },

    _draw: function (callback) {
      var ctx = this.canvas_ctx;
      ctx.textAlign = "left";
      ctx.textBaseline = "top";
      this._draw_lines(
        function () {
          this._draw_nodes(callback);
        }.bind(this),
      );
    },

    _watermark: function () {
      var c = this.canvas_elem;
      var ctx = this.canvas_ctx;
      ctx.textAlign = "right";
      ctx.textBaseline = "bottom";
      ctx.fillStyle = "#000";
      ctx.font = "11px Verdana,Arial,Helvetica,sans-serif";
      ctx.fillText("github.com/hizzgdev/jsmind", c.width - 5.5, c.height - 2.5);
      ctx.textAlign = "left";
      ctx.fillText($w.location, 5.5, c.height - 2.5);
    },

    _draw_lines: function (callback) {
      this.jm.view.graph.copy_to(this.canvas_ctx, callback);
    },

    _draw_nodes: function (callback) {
      var nodes = this.jm.mind.nodes;
      var node;
      for (var nodeid in nodes) {
        node = nodes[nodeid];
        this._draw_node(node);
      }

      function check_nodes_ready() {
        console.log("check_node_ready" + new Date());
        var allOk = true;
        for (var nodeid in nodes) {
          node = nodes[nodeid];
          allOk = allOk & node.ready;
        }

        if (!allOk) {
          $w.setTimeout(check_nodes_ready, 200);
        } else {
          $w.setTimeout(callback, 200);
        }
      }
      check_nodes_ready();
    },

    _draw_node: function (node) {
      var ctx = this.canvas_ctx;
      var view_data = node._data.view;
      var node_element = view_data.element;
      var ncs = getComputedStyle(node_element);
      if (!is_visible(ncs)) {
        node.ready = true;
        return;
      }

      var bgcolor = css(ncs, "background-color");
      var round_radius = parseInt(css(ncs, "border-top-left-radius"));
      var color = css(ncs, "color");
      var padding_left = parseInt(css(ncs, "padding-left"));
      var padding_right = parseInt(css(ncs, "padding-right"));
      var padding_top = parseInt(css(ncs, "padding-top"));
      var padding_bottom = parseInt(css(ncs, "padding-bottom"));
      var text_overflow = css(ncs, "text-overflow");
      var font =
        css(ncs, "font-style") +
        " " +
        css(ncs, "font-variant") +
        " " +
        css(ncs, "font-weight") +
        " " +
        css(ncs, "font-size") +
        "/" +
        css(ncs, "line-height") +
        " " +
        css(ncs, "font-family");

      var rb = {
        x: view_data.abs_x,
        y: view_data.abs_y,
        w: view_data.width + 1,
        h: view_data.height + 1,
      };
      var tb = {
        x: rb.x + padding_left,
        y: rb.y + padding_top,
        w: rb.w - padding_left - padding_right,
        h: rb.h - padding_top - padding_bottom,
      };

      ctx.font = font;
      ctx.fillStyle = bgcolor;
      ctx.beginPath();
      jcanvas.rect(ctx, rb.x, rb.y, rb.w, rb.h, round_radius);
      ctx.closePath();
      ctx.fill();

      ctx.fillStyle = color;
      if ("background-image" in node.data) {
        var backgroundUrl = css(ncs, "background-image").slice(5, -2);
        node.ready = false;
        var rotation = 0;
        if ("background-rotation" in node.data) {
          rotation = node.data["background-rotation"];
        }
        jcanvas.image(ctx, backgroundUrl, rb.x, rb.y, rb.w, rb.h, round_radius, rotation, function () {
          node.ready = true;
        });
      }
      if (!!node.topic) {
        if (text_overflow === "ellipsis") {
          jcanvas.text_ellipsis(ctx, node.topic, tb.x, tb.y, tb.w, tb.h);
        } else {
          var line_height = parseInt(css(ncs, "line-height"));
          jcanvas.text_multiline(ctx, node.topic, tb.x, tb.y, tb.w, tb.h, line_height);
        }
      }
      if (!!view_data.expander) {
        this._draw_expander(view_data.expander);
      }
      if (!("background-image" in node.data)) {
        node.ready = true;
      }
    },

    _draw_expander: function (expander) {
      var ctx = this.canvas_ctx;
      var ncs = getComputedStyle(expander);
      if (!is_visible(ncs)) {
        return;
      }

      var style_left = css(ncs, "left");
      var style_top = css(ncs, "top");
      var font = css(ncs, "font");
      var left = parseInt(style_left);
      var top = parseInt(style_top);
      var is_plus = expander.innerHTML === "+";

      ctx.lineWidth = 1;

      ctx.beginPath();
      ctx.arc(left + 7, top + 7, 5, 0, Math.PI * 2, true);
      ctx.moveTo(left + 10, top + 7);
      ctx.lineTo(left + 4, top + 7);
      if (is_plus) {
        ctx.moveTo(left + 7, top + 4);
        ctx.lineTo(left + 7, top + 10);
      }
      ctx.closePath();
      ctx.stroke();
    },

    _download: function () {
      var c = this.canvas_elem;
      var name = this.jm.mind.name + ".png";

      if (navigator.msSaveBlob && !!c.msToBlob) {
        var blob = c.msToBlob();
        navigator.msSaveBlob(blob, name);
      } else {
        var bloburl = this.canvas_elem.toDataURL();
        var anchor = $c("a");
        if ("download" in anchor) {
          anchor.style.visibility = "hidden";
          anchor.href = bloburl;
          anchor.download = name;
          $d.body.appendChild(anchor);
          var evt = $d.createEvent("MouseEvents");
          evt.initEvent("click", true, true);
          anchor.dispatchEvent(evt);
          $d.body.removeChild(anchor);
        } else {
          location.href = bloburl;
        }
      }
    },

    jm_event_handle: function (type, data) {
      if (type === jsMind.event_type.resize) {
        this.resize();
      }
    },
  };

  var screenshot_plugin = new jsMind.plugin("screenshot", function (jm) {
    var jss = new jsMind.screenshot(jm);
    jm.screenshot = jss;
    jm.shoot = function () {
      jss.shoot();
    };
    jm.add_event_listener(function (type, data) {
      jss.jm_event_handle.call(jss, type, data);
    });
  });

  jsMind.register_plugin(screenshot_plugin);
})(window);
